import json
import queue
import socket
import sys
import threading
import time
import ctypes
import os
import tkinter as tk
from logging.handlers import RotatingFileHandler
from tkinter  import Tk, Canvas

import websocket
from getmac import get_mac_address
# import mss
from pystray import Icon, MenuItem, Menu
import numpy as np
import requests
import yaml
from PIL import Image, ImageTk
from screeninfo import get_monitors
import logging

class Screensaver:
    def __init__(self, timeout=300, image_folder="./static/img",video_path="",changeImgTime=5):
        self.logger=self.run_log()
        self.logger.info(f"日志模块加载完毕")
        self.last_screenshot='';
        self.checkVersionUrl = yinetConfig['yinet']['checkVersionUrl']
        self.logger.info(f"客户端版本：{self.checkVersionUrl}")
        # MAC 地址
        self.MAC = get_mac_address().replace(":","-").upper()
        self.logger.info(f"获取MAC地址：{self.MAC}")
        self.socket_beat_time = yinetConfig['yinet']['socket_beat_time']
        #屏保超时时间
        self.timeout = timeout
        # 屏保图片切换时间
        self.checkMacStatusTime = int(yinetConfig['yinet']['check_mac_status_time'])
        # 屏保图片切换时间
        self.changeImgTime = int(changeImgTime)
        # 图片文件夹
        self.image_folder = image_folder
        self.video_path = video_path
        self.logger.info(f"开始加载线上图片")

        self.images = self.load_local_Img()
        # 当前图片索引
        self.current_image_index = 0
        self.downloadNewImgFlg = False
        # 最后活动时间
        self.last_activity = time.time()
        # 屏保状态
        self.is_screensaver_active = False
        # 当前版本号
        self.current_version = yinetConfig['yinet']['current_version']  # 当前版本号
        # 更新数据
        self.update_data={}
        # 获取所有屏幕的信息
        self.screens = get_monitors()
        # 创建窗口列表
        self.windows = []
        # 创建窗口列表
        self.canvas_objects = []  # 存储每个屏幕的 canvas 对象
        self.photo_images = []
        self.Status=True
        #长时间待机 则不获取鼠标键盘上次操作时间事件
        self.longTimeStop=False

        #托盘
        self.icon ={}
        self.rroot_Flg=True
        self.rroot2_Flg=True
        self.rroot_up =None
        self.queue = queue.Queue()

        self.TpWindow = False;

    def start_root_thread(self):
        """启动线程创建新窗口"""
        threading.Thread(target=self.create_window, daemon=True).start()
    def create_window(self):
        """子线程通知主线程创建窗口"""
        self.queue.put("new_window")


    def close_all_window(self):
        if self.TpWindow:
            self.is_screensaver_active = False
            self.TpWindow = False;
    def open_new_window(self):
        """在主线程中创建一个新窗口"""
        new_window = tk.Toplevel(self.rroot)
        return  new_window
    def is_valid_jpg(self,jpg_file):
        #  判断jpg文件下载是否完整
        if jpg_file.split('.')[-1].lower() == 'jpg':
            with open(jpg_file, 'rb') as f:
                f.seek(-2, 2)
                return  f.read() == b'\xff\xd9'
        else:
            return True
    def load_images(self):
        normalPicDataList = []

        #根据mac获取图片，如果获取不到则使用常规获取
        getImgByMac = f"{yinetConfig['yinet']['server']}{yinetConfig['yinet']['get_img_mac_url']}/{self.MAC}"
        try:
            mac_response = requests.get(getImgByMac)
            # 快速检查状态码 如果不是 2xx 则抛出异常
            mac_response.raise_for_status()
            normalPicDataList = mac_response.json()
            if normalPicDataList is not None and len(normalPicDataList) > 0:
                self.logger.info("开始下载指定mac地址图片")
        except:
            normalPicDataList = []
        if normalPicDataList is None or len(normalPicDataList) == 0:
            get_img_normal_url = f"{yinetConfig['yinet']['server']}{yinetConfig['yinet']['get_img_normal_url']}"
            try:
                response = requests.get(get_img_normal_url)
                # 快速检查状态码 如果不是 2xx 则抛出异常
                response.raise_for_status()
                normalPicDataList = response.json()
            except:
                normalPicDataList = []
        else:
            update_img_flg_url = f"{yinetConfig['yinet']['server']}{yinetConfig['yinet']['update_img_flg_url']}/{self.MAC}"
            response = requests.get(update_img_flg_url)

        dataPicLen = len(normalPicDataList)
        images = []

        server_imgs=[]
        for entity in normalPicDataList:
            if not os.path.exists(image_folder+"/"+entity['fileName']):
                try:
                    self.downLoadFile(entity['id'], image_folder)
                except Exception as e:
                    continue
            server_imgs.append(entity['fileName'])
        self.logger.info("读取文件夹路径============》")
        self.logger.info(self.image_folder)
        image_local=os.listdir(self.image_folder)

        for file in image_local:
            if dataPicLen==0:
                images.append(os.path.join(self.image_folder, file))

            #判断文件是否在系统设置文件中
            if file.split("/")[-1] in server_imgs:
                if file.lower().endswith((".png", ".jpg", ".jpeg")):
                    images.append(os.path.join(self.image_folder, file))
            else:
                if dataPicLen!=0 :
                    os.remove(self.image_folder+"/"+file)
                else:
                    images.append(os.path.join(self.image_folder, file))
        # for file in os.listdir(self.image_folder):
        #     # 判断文件是否在系统设置文件中
        #     if file.lower().endswith((".png", ".jpg", ".jpeg")):
        #         images.append(os.path.join(self.image_folder, file))
        # 加载文件夹中的所有图片

        if not images:
            self.logger.error("获取图片失败，10秒后重新获取")
            time.sleep(10)
            self.load_images();
            # raise ValueError("图片文件夹为空，请添加图片。路径地址："+str(self.image_folder))
        self.images = images

        return images
    def load_local_Img(self) :
        image_local = os.listdir(self.image_folder)
        images=[]
        for file in image_local:
                images.append(os.path.join(self.image_folder, file))
        return images
    #获取mac地址
    def getUserMac(self):
        # 获取物理网卡的MAC地址，返回的是字符串
        mac_address = get_mac_address()
        return mac_address.upper()
    # 检测用户最后的活动时间（鼠标或键盘）
    def get_last_input_time(self):
        if self.longTimeStop and self.is_screensaver_active:
            return  self.timeout-1
        class LASTINPUTINFO(ctypes.Structure):
            _fields_ = [("cbSize", ctypes.c_uint), ("dwTime", ctypes.c_ulong)]

        last_input_info = LASTINPUTINFO()
        last_input_info.cbSize = ctypes.sizeof(LASTINPUTINFO)
        ctypes.windll.user32.GetLastInputInfo(ctypes.byref(last_input_info))
        try:
            self.logger.info("进入到GetTickCount64")
            millis = ctypes.windll.kernel32.GetTickCount64() - last_input_info.dwTime
        except Exception:
            self.logger.info("GetTickCount64调用失败")
            millis = ctypes.windll.kernel32.GetTickCount() - last_input_info.dwTime

        self.logger.info("第一次-----距离上次键盘鼠标操作"+str(millis / 1000))
        # if millis / 1000 < self.timeout:
        #     self.exit_screensaver()
        if millis<0:
            last_input_time = last_input_info.dwTime
            # 获取当前时间
            current_time = ctypes.windll.kernel32.GetTickCount()
            # 检测溢出情况并计算时间差
            if current_time < last_input_time:  # 溢出检测
                millis = (2 ** 32 - last_input_time) + current_time
                self.logger.info("第二次--溢出-----距离上次键盘鼠标操作" + str(millis / 1000))
            else:
                millis = current_time - last_input_time
                self.logger.info("第二次--else-----距离上次键盘鼠标操作" + str(millis / 1000))
        if millis / 1000 >100000:
            self.longTimeStop=True
        return millis / 1000

    #检测屏幕截图有没有变化
    def get_screen_region_screenshot(self):
        """
        获取屏幕指定区域的截图
        """
        # try:
        #     # 使用 mss 截图工具
        #     with mss.mss() as sct:
        #         # 获取所有屏幕的监视器信息
        #         monitors = sct.monitors
        #         # 捕获整个桌面区域（包含所有屏幕）
        #         monitor = monitors[0]  # 监视器[0] 表示所有屏幕
        #         #只截取中间屏幕部分，
        #         monitor['height'] = monitor['height'] - 350
        #         monitor['top'] = 150
        #         all_screenshot = sct.grab(monitor)
        #         # 转换为 PIL.Image 对象，便于后续处理
        #         screenshot = Image.frombytes("RGB", all_screenshot.size, all_screenshot.rgb)
        # except OSError as e:
        #     logging.error("获取屏幕失败，返回上次页面")
        #     screenshot=self.last_screenshot
        # return np.array(screenshot)
        return  None;

    #对比图像有没有变化。
    def monitor_screen_region_changes(self):
        """
        监控屏幕指定区域的像素变化
        """
        #上一次的页面变化
        previous_screenshot = self.last_screenshot
        #获取当前页面的截图
        current_screenshot = self.get_screen_region_screenshot()
        if np.array_equal(previous_screenshot, current_screenshot):
            print("页面无变化")
        else:
            print("指定区域的像素发生变化")
            # 更新前一次的截图
            self.last_screenshot = current_screenshot
            return True
        return False


    def button_star_screensaver(self):
        self.is_screensaver_active = False
        self.start_screensaver()
    def start_screensaver(self):
        self.logger.info("开始进入屏保")
        self.prevent_screensaver()
        self.logger.info(f"激活状态is_screensaver_active:{self.is_screensaver_active}")
        if self.is_screensaver_active:
            return
        if len(self.images) ==0:
            return
        self.is_screensaver_active = True
        self.logger.info("开始进入屏保")

        # try:
        #     # 获取后台参数信息
        #     checkTimeRes = requests.get(
        #         config['yinet']['server'] + config['yinet']['get_config_url'] + "?configKey=checkTime",timeout=2)
        #     checkTime = json.loads(checkTimeRes.text)['checkTime']
        #     changeImgTimeRes = requests.get(
        #         config['yinet']['server'] + config['yinet']['get_config_url'] + "?configKey=changeImgTime",timeout=2)
        #     checkMacStatusTime = requests.get(
        #         config['yinet']['server'] + config['yinet']['get_config_url'] + "?configKey=checkMacStatusTime",timeout=2)
        #     changeImgTime = json.loads(changeImgTimeRes.text)['changeImgTime']
        #     self.logger.info("获取参数checkTime：" + str(checkTime))
        #     self.logger.info("获取参数changeImgTime：" + str(changeImgTime))
        #     self.logger.info("获取参数checkMacStatusTime：" + str(checkMacStatusTime))
        #     self.timeout = int(checkTime);
        #     self.changeImgTime = int(changeImgTime);
        #     self.checkMacStatusTime = int(checkMacStatusTime);
        # except Exception as e:
        #     self.logger.info("获取后台参数失败")

        self.windows = []
        self.canvas_objects = []
        self.photo_images = []

        index=0;
        for screen in self.screens:
            index=index+1;
            self.logger.info("第"+str(index)+"屏幕")
            if(index==1):
                root = tk.Toplevel(main_root)
                # self.rroot.attributes("-fullscreen", True)
                # self.rroot.configure(bg="black")
                root.wm_attributes('-topmost', True)
                root.overrideredirect(True)
                root.geometry(f"{screen.width}x{screen.height}+{screen.x}+{screen.y}")
                # root.geometry(f"300x200+100+100")
            else:
                root = tk.Toplevel(main_root)
                root.overrideredirect(True)
                root.wm_attributes('-topmost', True)
                # root.title("第"+str(index)+"屏幕窗口")
                # root.geometry(f"400x300+{screen.x + 100}+{screen.y + 100}")
                root.geometry(f"{screen.width}x{screen.height}+{screen.x}+{screen.y}")
                # root.geometry(f"300x200+{screen.x+ 100}+{screen.y + 100}")
            canvas = Canvas(root, bg="black")
            canvas.pack(fill="both", expand=True)
            self.canvas_objects.append(canvas)
            #进入屏保中
            self.show_images(canvas, root, screen)
            root.focus_set()  # 调用focus_set使得窗口获得焦点
            self.windows.append(root)
            # root.bind("<Escape>", lambda event: self.exit_screensaver())
        windex=0
        while windex < len(self.windows):
            self.logger.info("进入屏保加载。。。")
            all_root["window_" + str(windex)] = self.windows[windex]
            self.logger.info("设置第" + str(windex) + "屏。。。")
            self.logger.info(f"window_{windex}")
            self.logger.info(f"{all_root}")
            # all_root["window_" + str(windex)].bind("<Motion>", lambda event: self.exit_screensaver())
            # all_root["window_" + str(windex)].bind("<Key>", lambda e: self.exit_screensaver())
            all_root["window_" + str(windex)].bind("<Escape>", lambda event: self.exit_screensaver())
            windex += 1
        time.sleep(2)
        for wind in range(len(self.windows)):
            self.windows[wind].bind("<Motion>", lambda event: self.exit_screensaver())
            self.windows[wind].bind("<Key>", lambda e: self.exit_screensaver())



        # for  index,window in enumerate(self.windows):
        #     self.logger.info("进入屏保加载。。。")
        #     all_root["window_"+str(index)] = window
        #     # time.sleep(3)
        #     self.logger.info("设置第"+str(index)+"屏。。。")
        #     all_root["window_"+str(index)].bind("<Motion>", lambda event: self.exit_screensaver())
        #     all_root["window_"+str(index)].bind("<Key>", lambda e: self.exit_screensaver())

    # 阻止屏幕保护或系统睡眠启动
    def prevent_screensaver(self):
        ES_CONTINUOUS = 0x80000000
        ES_DISPLAY_REQUIRED = 0x00000002
        """
        阻止屏幕保护或系统睡眠启动
        """
        ctypes.windll.kernel32.SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED)
    def on_focus_set(self,event):
        print("Window is focused")
    def show_images(self, canvas, root, screen):
        def update_image():
            if not self.is_screensaver_active:
                root.destroy()
                return
            print(f"播放第 {self.current_image_index} 张照片")
            img_path = self.images[self.current_image_index]
            img = Image.open(img_path)
            img = img.resize((screen.width, screen.height), Image.Resampling.LANCZOS)
            photo_image = ImageTk.PhotoImage(img)
            canvas.create_image(0, 0, anchor="nw", image=photo_image)
            self.photo_images.append(photo_image)  # 保存引用，避免被回收
            if  len(self.images)==1:
                self.current_image_index=0
            else:
                self.current_image_index = (self.current_image_index + 1) % len(self.images)

            root.after(self.changeImgTime*1000, update_image)

        update_image()


    def exit_screensaver(self):
        if self.is_screensaver_active:
            self.is_screensaver_active = False
            #设置长时间不操作键盘 状态关闭
            self.longTimeStop=False;
            for index, window in enumerate(self.windows):
                print("关闭di" + str(index))
                if all_root["window_" + str(index)].winfo_exists():
                    close_window("window_" + str(index))
            # close_window("window_" + str(0))
            self.windows.clear()
            self.canvas_objects.clear()
            self.photo_images.clear()
            self.last_activity = time.time()

    def setup_tray(self):

        """设置系统托盘图标"""
        # 创建托盘菜单
        menu = Menu(
            MenuItem("进入屏保", self.button_star_screensaver),
            MenuItem("更新图片", self.downLoadNewImg),
            MenuItem("检测更新", self.opencheckWindow),
            MenuItem("退出", self.on_exit),
        )

        # 创建系统托盘图标
        self.icon = Icon("屏幕保护", self.create_desk_image(), "屏幕保护", menu)
        self.icon.run()

    def on_exit(self):
        self.logger.info("退出")
        self.Status=False;
        """退出程序"""
        self.icon.stop()  # 停止托盘图标
        killExe()
        # self.rroot.destroy()
        return True

    def create_desk_image(self):
        logo_ico_path = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0]))+"/static/", 'logo.ico')
        return Image.open(logo_ico_path)

    def on_message(self,ws, message):
        """接收消息时触发"""
        print(f"[服务器响应] {message}")
        if message == "PONG":
            print("[心跳确认] 服务器响应正常")
        elif "NEW_IMG" in message:
            self.logger.info("发现待更新图片")
            self.downLoadNewImg()

    def on_error(self,ws, error):
        """出现错误时触发"""
        print(f"[错误] {error}")

    def on_close(self,ws, close_status_code, close_msg):
        """连接关闭时触发"""
        print("[连接关闭]")
        time.sleep(self.checkMacStatusTime)
        self.start_client()

    def on_open(self,ws):
        """连接成功时触发"""
        self.logger.info(f"{self.MAC}机器[连接建立]")
        def send_heartbeat():
            """发送心跳消息"""
            while True:
                try:
                    ws.send("PING")
                    print("[心跳发送] PING")
                    time.sleep(yinetConfig['yinet']['socket_beat_time'])  # 每5秒发送一次心跳
                except Exception as e:
                    print(f"[发送失败] {e}")
                    break
            # 启动心跳线程

        heartbeat_thread = threading.Thread(target=send_heartbeat, daemon=True)
        heartbeat_thread.start()
    #下载新图片
    def downLoadNewImg(self):
        self.logger.info("下载新图片")
        if self.downloadNewImgFlg:
            return
        self.logger.info(f"downloadNewImgFlg 为False 进入下载 {self.downloadNewImgFlg}")
        self.downloadNewImgFlg=True
        """
        下载新图片并更新屏保状态。
        本函数旨在下载新的图片，并在下载过程中管理屏保的状态。它首先退出当前的屏保，
        清空图片列表，然后下载新图片，最后更新屏保状态。
        """
        #下载图片时退出屏保
        self.exit_screensaver()
        # 设置为True 下载图片期间不进入屏保
        self.is_screensaver_active = True
        self.logger.info("退出屏保")
        #设置图片为空
        self.images=[]
        self.current_image_index=0
        #重新加载图片
        self.logger.info("重新加载图片")
        self.load_images();
        self.logger.info("加载图片完毕")
        #改变状态位 表示可以进入屏保中
        self.is_screensaver_active = False
        #重置下载图片状态位
        self.downloadNewImgFlg = False

    #发送心跳
    #连接服务器scoket
    def start_client(self,):
        # client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        ws_server_url = f"{yinetConfig['yinet']['server_socket']}/{self.MAC}"
        # 创建 WebSocket 客户端
        ws = websocket.WebSocketApp(ws_server_url,
                                    on_open=self.on_open,
                                    on_message=self.on_message,
                                    on_error=self.on_error,
                                    on_close=self.on_close)
        # 运行客户端
        ws.run_forever()
    def checkMacStatus(self):
        while True:
            try:
                getFlgByMac = f"{yinetConfig['yinet']['server']}{yinetConfig['yinet']['get_mac_flg_url']}/{self.MAC}"
                response = requests.get(getFlgByMac)
                if response.status_code == 200:
                    macJsonData = json.loads(response.text)
                    pictureUpdateStatus=macJsonData['pictureUpdateStatus']
                    if pictureUpdateStatus==0:
                        self.downLoadNewImg()
                    else:
                        self.logger.info("无更新")
            except Exception:
                self.logger.info("获取更新状态失败")
            time.sleep(self.checkMacStatusTime)

    # 下载文件资源
    def downLoadFile(self,dataId,currFilePath):
        try:
            download_url = f"{yinetConfig['yinet']['server']}{yinetConfig['yinet']['download_url']}"
            response = requests.get(download_url, params={'id': dataId}, stream=True)
            response.raise_for_status()  # 检查请求是否成功
            # 提取文件名
            content_disposition = response.headers.get('Content-Disposition')
            if content_disposition:
                filename = content_disposition.split('filename=')[1].strip('"')
                filename = filename.encode('iso-8859-1').decode('utf-8')  # 处理中文文件名
            else:
                filename = 'downloaded_file'
            currFileFullPath =  os.path.join(currFilePath,filename)
            #如果屏保文件使用目录只有一个，且与当前处理的文件名称一致，则跳过
            # 死循环保存文件，直到成功
            while True:
                try:
                    if os.path.isfile(currFileFullPath) and len(os.listdir(currFilePath)) == 1:
                        break
                    with open(currFileFullPath, 'wb') as f:
                        for chunk in response.iter_content(chunk_size=8192):  # 每次读取8KB
                            f.write(chunk)

                    #print(f'文件下载成功: {currFileFullPath}')
                    break  # 如果成功，跳出循环
                except IOError:
                    #print(f'文件 {currFileFullPath} 正在被使用，稍后重试...')
                    time.sleep(5)  # 等待1秒后重试
        except Exception as e:
            logging.exception('发生错误：' + e)

    #开启日志
    def run_log(self):
        print("启动日志模块")
        log_dir_name = "logs/"
        log_file_name = 'logger-' + time.strftime('%Y-%m-%d', time.localtime(time.time())) + '.log'

        # 创建文件夹
        path = log_dir_name.strip()
        if not os.path.exists(path):
            os.makedirs(path)
        for filename in os.listdir(log_dir_name):
            if filename is not log_file_name:
                os.remove(os.path.join(log_dir_name, filename))
        # 创建一个日志记录器
        logger = logging.getLogger(__name__)

        # 创建一个文件处理器
        file_handler = RotatingFileHandler(log_dir_name + log_file_name, maxBytes=1024 * 1024 * 20, backupCount=30)
        print("日志级别是否开启："+str(yinetConfig['yinet']['DeBug']))
        if not yinetConfig['yinet']['DeBug']:
            logger.setLevel(logging.WARN)  # 设置日志级别
            file_handler.setLevel(logging.WARN)  # 可以为处理器设置不同的级别
        else:
            logger.setLevel(logging.DEBUG)  # 设置日志级别
            file_handler.setLevel(logging.DEBUG)  # 可以为处理器设置不同的级别
        # 创建一个控制台处理器
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.INFO)  # 仅将 INFO 及以上级别的日志输出到控制台
        # # 设置日志的记录等级
        # file_handler.basicConfig(level=logging.INFO)  # 调试debug级
        # # 创建日志记录器，指明日志保存的路径、每个日志文件的最大大小、保存的日志文件个数上限
        # file_log_handler = RotatingFileHandler(log_dir_name + log_file_name, maxBytes=1024 * 1024 * 20, backupCount=30)
        # 创建日志记录的格式 日志等级 输入日志信息的文件名 行数 日志信息
        formatter = logging.Formatter('%(levelname)s %(filename)s:%(lineno)d %(message)s')
        # 为刚创建的日志记录器设置日志记录格式
        file_handler.setFormatter(formatter)
        console_handler.setFormatter(formatter)
        # 为全局的日志工具对象（flask app使用的）添加日志记录器
        # logging.getLogger().addHandler(file_log_handler)
        # 将处理器添加到日志记录器
        logger.addHandler(file_handler)
        logger.addHandler(console_handler)

        logger.info('日志模块启动成功')
        return  logger


    #检测是否有新版本
    def opencheckWindow(self):
        self.ooppcckkee()

    def ooppcckkee(self):
        update_url = yinetConfig['yinet']['server'] + "/" + self.checkVersionUrl
        responseVersionData = requests.get(update_url)
        latest_version = responseVersionData.json().get("version")
        version_msg = responseVersionData.json().get("msg")
        # if latest_version != self.current_version:
        self.responseVersionData=responseVersionData

        self.show_check_window()

    def button_upload_exe_download(self,event):
        threading.Thread(target=self.download_exe_to_update,daemon=True).start()
        # self.download_exe_to_update()
    def download_exe_to_update(self):
        latest_version = self.responseVersionData.json().get("version")
        download_url = self.responseVersionData.json().get("download_url")
        url = yinetConfig['yinet']['server'] + download_url
        """
        下载 exe 文件并运行
        :param url: 文件的下载地址
        :param save_path: 保存文件的路径
        """
        save_path = os.path.dirname(
            os.path.realpath(sys.argv[0])) + "/static/" + "Yinet安装包.exe"
        try:
            # 开始下载
            self.logger.info(f"正在从 {url} 下载文件...")
            self.update_data['over_text'].set("正在从服务器下载文件...")
            with requests.get(url, stream=True) as response:
                response.raise_for_status()
                with open(save_path, "wb") as file:
                    for chunk in response.iter_content(chunk_size=8192):  # 分块下载
                        file.write(chunk)
            self.logger.info(f"下载完成，文件已保存到 {save_path}")
            self.update_data['over_text'].set(f"下载完成，文件已保存到 {save_path}")
            # 打开下载的 exe 文件
            self.logger.info("正在运行安装程序...")
            self.update_data['over_text'].set(f"正在运行安装程序...")
            # 以管理员权限运行指定程序
            try:
                self.run_with_admin_startfile(save_path)
                self.Status=False
                killExe();
                # os.startfile(os.path.dirname(os.path.realpath(sys.argv[0])) + "/sa.bat")
            except:
                self.logger.info("更新调用失败，调用startfile进行更新")
                os.startfile(save_path)
                killExe();
            # os.startfile(save_path)# 打开安装程序

        except requests.exceptions.RequestException as e:
            self.update_data['over_text'].set(f"下载失败：{e}")
            self.logger.info(f"下载失败：{e}")
        except Exception as e:
            self.update_data['over_text'].set(f"运行失败：{e}")
            self.logger.info(f"运行失败：{e}")


    def run_with_admin_startfile(self,executable):
        print("executable:"+executable)
        ctypes.windll.shell32.ShellExecuteW(None, "runas", executable, None, None, 1)


    def show_check_window(self):
        self.TpWindow=True;
        latest_version = self.responseVersionData.json().get("version")
        version_msg = self.responseVersionData.json().get("msg")



        # root =  self.open_new_window()
        root = tk.Toplevel(main_root)
        root.title("屏幕保护")
        # 获取屏幕宽度和高度
        screen_width = root.winfo_screenwidth()
        screen_height = root.winfo_screenheight()
        # 计算窗口的起始坐标
        x = (screen_width - 400) // 2
        y = (screen_height - 300) // 2
        # 设置窗口的位置和大小
        root.geometry(f"{400}x{300}+{x}+{y}")
        # 使用 StringVar 绑定动态文本
        self.update_data['version_label_var'] = tk.StringVar()
        self.update_data['update_msg_var'] = tk.StringVar()
        self.update_data['over_text'] = tk.StringVar()
        tk.Label(root, text="当前版本：" + str(self.current_version), font=("Arial", 12)).pack(pady=10)
        # 设置初始值
        if latest_version != self.current_version:
            self.update_data['version_label_var'].set(f"发现新版本: 屏幕保护{latest_version}")
            self.update_data['update_msg_var'].set(f"更新内容：{version_msg}")
            tk.Button(root, text="点击下载更新", font=("Arial", 14),
                      command=lambda: self.button_upload_exe_download(None)).pack()
        else:
            self.update_data['version_label_var'].set(f"已是最新版本")
        self.update_data['over_text'].set(f"")
        tk.Label(root, textvariable=self.update_data['version_label_var'], fg="#eb3235",
                 font=("Arial", 14)).pack(pady=10)
        tk.Label(root, textvariable=self.update_data['update_msg_var'], font=("Arial", 12)).pack(pady=10)
        tk.Label(root, textvariable=self.update_data['over_text'], font=("Arial", 12)).pack(pady=10)
        # root.protocol("WM_DELETE_WINDOW", self.on_closing)
        # root.mainloop()
        all_root["CheckWindow"]=root
    def on_closing(self):
        self.logger.info("111")
        # self.queue.put("close_all_window")
        close_window("CheckWindow")
    #启动程序
    def monitor_activity(self):

        # 启动托盘
        threading.Thread(target=self.setup_tray, daemon=True).start()
        # 下载图片
        threading.Thread(target=self.load_images, daemon=True).start()
        # 连接服务器
        threading.Thread(target= self.start_client, daemon=True).start()
        # 检查是否有更新
        threading.Thread(target= self.checkMacStatus, daemon=True).start()

        while True:
            try:
                idle_time = self.get_last_input_time()
            except Exception as e:
                self.logger.info("获取idle_time失败："+str(e))
                if self.is_screensaver_active:
                    idle_time=self.timeout-1

            #monitor_screen_region_changes（） 检测5秒前屏幕是否与当前屏幕有变化，如果有则不进入到屏保页面。
            # if not self.monitor_screen_region_changes() and idle_time > self.timeout and not self.is_screensaver_active:
            if  idle_time > self.timeout and not self.is_screensaver_active:
                self.logger.info("当前检测时间间隔："+str(self.timeout)+"距离上次操作鼠标键盘时间"+str(idle_time))
                self.logger.info(idle_time > self.timeout )
                self.start_screensaver()
            time.sleep(5)  # 每秒检测一次


# 创建一个全局的队列，用来在主线程中处理来自其他线程的任务
task_queue = queue.Queue()
# 创建主窗口
main_root = tk.Tk()
all_root={}
def process_queue():
    try:
        while True:
            # 从队列中获取任务
            func, args, kwargs = task_queue.get_nowait()
            # 执行任务
            func(*args, **kwargs)
            # 标记任务完成
            task_queue.task_done()
    except queue.Empty:
        # 队列为空时，再次检查队列
        main_root.after(100, process_queue)

# 定义一个函数供其他线程调用，来安全地添加页面
def thread_safe_add_page(sroot,name):
    task_queue.put((add_new_page, (sroot,name,), {}))

# 定义一个函数供其他线程调用，来安全地添加页面
def killExe():
    main_root.destroy()

def add_new_page(roota,name):
    all_root[name]=roota
    print(name+"窗口进行加载")
    all_root[name].mainloop()

def close_window(name):
    try:
        print("关闭"+name+"窗口")
        all_root[name].destroy()
    except:
        print(name+"窗口：关闭错误")

if __name__ == "__main__":

    video_path = "./static/video"
    image_folder = "./static/img"
    #软件路径
    exe_path=os.path.dirname(os.path.realpath(sys.argv[0]))
    print("启动软件路径："+str(exe_path));
    # 读取 YAML 文件
    config_path = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), 'config.yaml')
    print("启动配置文件："+str(config_path))
    with open(config_path, 'r', encoding='utf-8') as file:
        config = yaml.safe_load(file)

    main_root.title("主窗口")
    main_root.withdraw()
    # 启动队列处理函数
    main_root.after(100, process_queue)
    # 获取值
    global yinetConfig
    yinetConfig= config
    image_folder=exe_path+"/static/img"
    video_path=config['yinet']['video_path']
    checkTime=config['yinet']['checkTime']
    changeImgTime=config['yinet']['changeImgTime']
    print(f"Database Host: {yinetConfig['yinet']['server']}")

    #创建文件夹
    if not os.path.exists(video_path):
        os.makedirs(video_path)
    if not os.path.exists(image_folder):
        os.makedirs(image_folder)

    #初始化屏保工具
    # 配置屏幕保护工具
    screensaver = Screensaver(
        timeout=int(checkTime),
        image_folder=image_folder,
        video_path=video_path + "/1_3.mp4", # 替换为你的视频路径
        changeImgTime= changeImgTime,
    )
    # global logger
    # 启动log
    # screensaver.run_log()
    # screensaver = Screensaver(timeout=3, image_folder=image_folder)
    # screensaver.monitor_activity()
    #启动屏保程序 线程
    threading.Thread(target=screensaver.monitor_activity, daemon=True).start()

    # 启动托盘
    # threading.Thread(target=screensaver.setup_tray, daemon=True).start()
    main_root.mainloop()
    while screensaver.Status:
        time.sleep(10)  # 主线程保持运行

    screensaver.logger.info("退出屏保")